package com.guang.executor.executorpool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author lg
 * @Description  线程池在放入任务的时候是惰性加载的，也就是说只有当任务来的时候，才会开始创建核心线程
 *               下面将会详细分析：
 *               测试案例将会描述以下现象：
 *               案例一：设置核心线程为1，最大线程数为2，阻塞队列为1，这个时候提交2个任务来，首先创建1个核心线程执行任务，另外一个放入到队列中
 *                      当核心线程执行完了任务之后，才会来执行队列中的任务；
 *               案例二：设置核心线程为1，最大线程数为2，阻塞队列为1，这个时候提交3个任务来，首先创建1个核心线程执行任务，另外一个放入到队列中
 *                      但是因为第三个任务无法被核心线程执行，也无法放入到队列中来，所以这个时候必要要创建核心线程数来进行执行
 * @date 2022/10/24 17:39
 */
public class ExecutorPoolTestLazy {
    private static Logger logger = LoggerFactory.getLogger(ExecutorPoolTestLazy.class);
    private static int CORE_THREAD_COUNT = Runtime.getRuntime().availableProcessors()+1;
    private static final String FIX_THREAD_NAME = "FixThreadPool_";
    // 不需要临时线程了，因为LinkedBlockingDeque默认长度是2的三十一次方-1
    private static final ThreadPoolExecutor EXECUTOR_SERVICE = new ThreadPoolExecutor(1,
            2,
            5, TimeUnit.SECONDS,
            new ArrayBlockingQueue(1),
            new ThreadFactory() {
                    AtomicInteger atomicInteger = new AtomicInteger(1);
                    // 自定义生产线程的工厂
                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r,FIX_THREAD_NAME+atomicInteger.getAndIncrement());
                }
            },new ThreadPoolExecutor.AbortPolicy()
    );

    public static void main(String[] args) throws InterruptedException {
        logger.info("当前线程池中的线程数大小是：{}",EXECUTOR_SERVICE.getPoolSize()); // 0
        EXECUTOR_SERVICE.execute(new MyTask());
        TimeUnit.SECONDS.sleep(2);
        logger.info("当前线程池中的线程数大小是：{}",EXECUTOR_SERVICE.getPoolSize()); // 1
        logger.info("执行两个任务。一个将会交给核心线程来执行任务，另外一个放入到队列中。等待核心线程执行完成任务之后，再次来执行队列中的任务");
        for (int i = 0; i < 2; i++) {
            EXECUTOR_SERVICE.execute(new MyTask());
        }
        TimeUnit.SECONDS.sleep(2);
        logger.info("执行完成两个任务后，此时核心线程是:{}",EXECUTOR_SERVICE.getPoolSize());
        for (int i = 0; i < 3; i++) {
            EXECUTOR_SERVICE.execute(new MyTask());
        }
        TimeUnit.SECONDS.sleep(2);
        logger.info("执行三个任务。核心队列执行一个，队列中放一个，剩下一个将会交给非核心线程来执行");
        logger.info("当前线程池中的数量为:{}",EXECUTOR_SERVICE.getPoolSize());
    }

    private static class MyTask implements Runnable{
        @Override
        public void run() {
            logger.info("在执行线程任务的时候打印当前线程名称:{}",Thread.currentThread().getName());
            // logger.info("start..........");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // logger.info("end..........");
        }
    }
}
